package nl.utwente.fmt.vertalerbouw.tarrh.treewalker;

import org.antlr.runtime.RecognitionException;

/**
 * Interface to allow multiple classes to walk over the abstract syntax trees.
 * 
 * @param <ExceptionType>
 *            the exception class that will be thrown by the implementing class.
 * @param <IfElse>
 *            the class holding data related to the if-else statements.
 * @param <WhileDo>
 *            the class holding data related to the while-do statements.
 * @param <TryCatch>
 *            the class holding data related to the try-catch statements.
 * @param <Expression>
 *            the class holding data related to return values from expressions.
 * @param <FunctionCall>
 *            the class holding data related to function calls.
 * @param <StatementExpression>
 *            the class holding data related to statement expressions.
 */
public interface TreeWalker<ExceptionType extends RecognitionException, IfElse, WhileDo, TryCatch, Expression, FunctionCall, StatementExpression> {
	/**
	 * Called after the occurence of a variable.
	 * 
	 * @param identifier
	 *            the identifier of the variable.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression accessVariable(String identifier) throws ExceptionType;

	/**
	 * Called after the occurence of the array index operator.
	 * 
	 * @param expr
	 *            the resulting object from the main expression.
	 * @param index
	 *            the resulting object from the index expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression arrayIndexAccess(Expression expr, Expression index) throws ExceptionType;

	/**
	 * Called after the occurence of an array index assignment.
	 * 
	 * @param identifier
	 *            the identifier of the variable.
	 * @param index
	 *            the resulting object from the index expression.
	 * @param expr
	 *            the resulting object from the expression containing the value
	 *            to be assigned.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression arrayIndexAssign(String identifier, Expression index, Expression expr)
			throws ExceptionType;

	/**
	 * Called after the occurence of an assigment.
	 * 
	 * @param identifier
	 *            the identifier of the variable.
	 * @param expr
	 *            the resulting object from the expression containing the value
	 *            to be assigned.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression assign(String identifier, Expression expr) throws ExceptionType;

	/**
	 * Called at the start of a class declaration.
	 * 
	 * @param className
	 *            the class name of the new class.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void classEnd(String className) throws ExceptionType;

	/**
	 * Called at the end of a class declaration.
	 * 
	 * @param className
	 *            the class name of the new class.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void classStart(String className) throws ExceptionType;

	/**
	 * Called after the occurence of a local variable declaration with an array
	 * type.
	 * 
	 * @param type
	 *            the type of the elements in the array.
	 * @param identifier
	 *            the identifier of the variable.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void declareArray(String type, String identifier) throws ExceptionType;

	/**
	 * Called after the occurence of a local constant declaration.
	 * 
	 * @param type
	 *            the type of the constant value.
	 * @param identifier
	 *            the identifier of the constant.
	 * @param expr
	 *            the resulting object from the expression containing the value
	 *            to be assigned to the constant.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void declareConstant(String type, String identifier, Expression expr) throws ExceptionType;

	/**
	 * Called after the occurence of a member variable declaration with an array
	 * type.
	 * 
	 * @param type
	 *            the type of the elements in the array.
	 * @param identifier
	 *            the identifier of the array.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void declareMemberArray(String type, String identifier) throws ExceptionType;

	/**
	 * Called after the occurence of a member constant declaration.
	 * 
	 * @param type
	 *            the type of the constant value.
	 * @param identifier
	 *            the identifier of the constant.
	 * @param expr
	 *            the resulting object from the expression containing the value
	 *            to be assigned to the constant.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void declareMemberConstant(String type, String identifier, Expression expr) throws ExceptionType;

	/**
	 * Called after the occurence of a member variable declaration.
	 * 
	 * @param type
	 *            the type of the variable value.
	 * @param identifier
	 *            the identifier of the variable.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void declareMemberVariable(String type, String identifier) throws ExceptionType;

	/**
	 * Called after the occurrence of a local variable declaration.
	 * 
	 * @param type
	 *            the type of the variable value.
	 * @param identifier
	 *            the identifier of the variable.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void declareVariable(String type, String identifier) throws ExceptionType;

	/**
	 * Called after the entire tree is processed.
	 * 
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void end() throws ExceptionType;

	/**
	 * Called after the occurrence of an expression statement.
	 * 
	 * @param expr
	 *            the resulting object from the expression.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void expressionStatement(Expression expr) throws ExceptionType;

	/**
	 * Called after the occurrence of an argument in a function declaration.
	 * 
	 * @param position
	 *            the position of the argument, starting at 0 for the first
	 *            argument.
	 * @param type
	 *            the type of argument variable.
	 * @param identifier
	 *            the identifier of the argument variable.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void functionArgument(int position, String type, String identifier) throws ExceptionType;

	/**
	 * Called after the arguments and before the function body in a function
	 * declaration.
	 * 
	 * @param returnType
	 *            the identifier of the function return value.
	 * @param functionName
	 *            the identifier of the function.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void functionBody(String returnType, String functionName) throws ExceptionType;

	/**
	 * Called after the occurrence of an argument in a function call.
	 * 
	 * @param call
	 *            the resulting object from the matching call to
	 *            functionCallStart.
	 * @param position
	 *            the position of the argument, starting at 0 for the first
	 *            argument.
	 * @param expr
	 *            the resulting object from expression containing the value for
	 *            this argument.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void functionCallArgument(FunctionCall call, int position, Expression expr) throws ExceptionType;

	/**
	 * Called at the end of a function call.
	 * 
	 * @param call
	 *            the resulting object from the matching call to
	 *            functionCallStart.
	 * @param argumentCount
	 *            the total number of arguments passed to the function.
	 * @param expr
	 *            the resulting object from the expression on which this member
	 *            function is to be executed.
	 * @param functionName
	 *            the identifier of the function to be called.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression functionCallEnd(FunctionCall call, int argumentCount, Expression expr,
			String functionName) throws ExceptionType;

	/**
	 * Called at the end of a function call.
	 * 
	 * @param call
	 *            the resulting object from the matching call to
	 *            functionCallStart.
	 * @param argumentCount
	 *            the total number of arguments passed to the function.
	 * @param functionName
	 *            the identifier of the function to be called.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression functionCallEnd(FunctionCall call, int argumentCount, String functionName)
			throws ExceptionType;

	/**
	 * Called at the start of a function call.
	 * 
	 * @param expr
	 *            the resulting object from the expression on which this member
	 *            function is to be executed.
	 * @param functionName
	 *            the identifier of the function to be called.
	 * @return an object that will be passed to all calls related to this
	 *         function call.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract FunctionCall functionCallStart(Expression expr, String functionName) throws ExceptionType;

	/**
	 * Called at the start of a function call.
	 * 
	 * @param functionName
	 *            the identifier of the function to be called.
	 * @return an object that will be passed to all calls related to this
	 *         function call.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract FunctionCall functionCallStart(String functionName) throws ExceptionType;

	/**
	 * Called at the end of a function declaration.
	 * 
	 * @param returnType
	 *            the identifier of the function return value.
	 * @param functionName
	 *            the identifier of the function.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void functionEnd(String returnType, String functionName) throws ExceptionType;

	/**
	 * Called at the start of a function declaration.
	 * 
	 * @param returnType
	 *            the identifier of the function return value.
	 * @param functionName
	 *            the identifier of the function.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void functionStart(String returnType, String functionName) throws ExceptionType;

	/**
	 * Called at the start of the else part of an if-else statement.
	 * 
	 * @param ifElse
	 *            the resulting object from the matching call to ifStart.
	 * @param expr
	 *            the resulting object from expression containing the value for
	 *            the if-else condition.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void ifElse(IfElse ifElse, Expression expr) throws ExceptionType;

	/**
	 * Called at the end of an if-else statement.
	 * 
	 * @param ifElse
	 *            the resulting object from the matching call to ifStart.
	 * @param expr
	 *            the resulting object from expression containing the value for
	 *            the if-else condition.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void ifEnd(IfElse ifElse, Expression expr) throws ExceptionType;

	/**
	 * Called at the start of an if-else statement.
	 * 
	 * @param expr
	 *            the resulting object from expression containing the value for
	 *            the if-else condition.
	 * @return an object that will be passed to all calls related to this
	 *         if-else statement.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract IfElse ifStart(Expression expr) throws ExceptionType;

	/**
	 * Called at the occurrence of a boolean literal.
	 * 
	 * @param value
	 *            the boolean value of the literal.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression literalBoolean(boolean value) throws ExceptionType;

	/**
	 * Called at the occurrence of an integer literal.
	 * 
	 * @param value
	 *            the integer value of the literal.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression literalInteger(int value) throws ExceptionType;

	/**
	 * Called at the occurrence of a string literal.
	 * 
	 * @param value
	 *            the string value of the literal.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression literalString(String value) throws ExceptionType;

	/**
	 * Called at the end of the main function.
	 * 
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void mainFunctionEnd() throws ExceptionType;

	/**
	 * Called at the start of the main function.
	 * 
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void mainFunctionStart() throws ExceptionType;

	/**
	 * Called at the occurrence of a new array creation.
	 * 
	 * @param type
	 *            the type of the elements of the array.
	 * @param expr
	 *            the resulting object from expression containing the size for
	 *            the new array.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression newArray(String type, Expression expr) throws ExceptionType;

	/**
	 * Called at the occurrence of a new instance creation.
	 * 
	 * @param type
	 *            the type of the instance
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression newObject(String type) throws ExceptionType;

	/**
	 * Called at the occurrence of the and operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorAnd(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the division operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorDivision(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the equals operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorEquals(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the greater operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorGreater(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the greater-or-equals operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorGreaterEquals(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the less operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorLess(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the less-or-equals operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorLessEquals(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the minus operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorMinus(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the modulo operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorModulo(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the multiply operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorMultiply(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the not-equals operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorNotEquals(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the or operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorOr(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of the plus operator.
	 * 
	 * @param expr1
	 *            the resulting object from left-hand side expression.
	 * @param expr2
	 *            the resulting object from right-hand side expression.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression operatorPlus(Expression expr1, Expression expr2) throws ExceptionType;

	/**
	 * Called at the occurrence of a print statement.
	 * 
	 * @param expr
	 *            the resulting object from expression whose result should be
	 *            printed.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void print(Expression expr) throws ExceptionType;

	/**
	 * Called at the occurrence of a read statement.
	 * 
	 * @param identifier
	 *            the identifier of the variable to which the resulting value
	 *            should be written.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void read(String identifier) throws ExceptionType;

	/**
	 * Called at the start of the tree.
	 * 
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void start() throws ExceptionType;

	/**
	 * Called at the end of a statement expression.
	 * 
	 * @param statementExpression
	 *            the resulting object from the matching call to
	 *            statementExpressionStart.
	 * @return the resulting expression object.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract Expression statementExpressionEnd(StatementExpression statementExpression) throws ExceptionType;

	/**
	 * Called at the start of a statement expression.
	 * 
	 * @return an object that will be passed to the ending call related to this
	 *         statement expression.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract StatementExpression statementExpressionStart() throws ExceptionType;

	/**
	 * Called at the occurrence of a throw statement.
	 * 
	 * @param expr
	 *            the resulting object from expression whose result should be
	 *            thrown
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void throwException(Expression expr) throws ExceptionType;

	/**
	 * Called at the end of the catch part of a try-catch statement.
	 * 
	 * @param tryCatch
	 *            the resulting object from the matching call to tryStart.
	 * @param type
	 *            the type of the catch variable.
	 * @param identifier
	 *            the identifier of the catch variable.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void tryCatchEnd(TryCatch tryCatch, String type, String identifier) throws ExceptionType;

	/**
	 * Called at the start of the catch part of a try-catch statement.
	 * 
	 * @param tryCatch
	 *            the resulting object from the matching call to tryStart.
	 * @param type
	 *            the type of the catch variable.
	 * @param identifier
	 *            the identifier of the catch variable.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void tryCatchStart(TryCatch tryCatch, String type, String identifier) throws ExceptionType;

	/**
	 * Called at the end of the try part of a try-catch statement.
	 * 
	 * @param tryCatch
	 *            the resulting object from the matching call to tryStart.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void tryEnd(TryCatch tryCatch) throws ExceptionType;

	/**
	 * Called at the start of the try part of a try-catch statement.
	 * 
	 * @return an object that will be passed to all calls related to this
	 *         try-catch statement.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract TryCatch tryStart() throws ExceptionType;

	/**
	 * Called after the condition of a while-do statement.
	 * 
	 * @param whileDo
	 *            the resulting object from the matching call to whileStart.
	 * @param expr
	 *            the resulting object from condition expression.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void whileCondition(WhileDo whileDo, Expression expr) throws ExceptionType;

	/**
	 * Called at the end of a while-do statement.
	 * 
	 * @param whileDo
	 *            the resulting object from the matching call to whileStart.
	 * @param expr
	 *            the resulting object from condition expression.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract void whileEnd(WhileDo whileDo, Expression expr) throws ExceptionType;

	/**
	 * Called at the start of a while-do statement.
	 * 
	 * @return an object that will be passed to all calls related to this
	 *         while-do statement.
	 * @throws ExceptionType
	 *             if an errors occurs.
	 */
	public abstract WhileDo whileStart() throws ExceptionType;
}
